#pragma once

#ifndef __MY_MSG_QUEUE__
#define __MY_MSG_QUEUE__

#include "../mqcommon/helpper.hpp"

#include <iostream>
#include <string>
#include <cassert>
#include <memory>
#include <mutex>
#include <unordered_map>

namespace NS_MsgQueue
{

    struct MsgQueue
    {
        using Ptr = std::shared_ptr<MsgQueue>;
        std::string name;
        bool durable;
        bool exclusive;
        bool auto_delete;
        google::protobuf::Map<std::string, std::string> args;

        MsgQueue(const std::string &qname, bool qexclusive, bool qdurable, bool qauto_delete, const google::protobuf::Map<std::string, std::string> &qargs)
            : name(qname), durable(qdurable), exclusive(qexclusive), auto_delete(qauto_delete), args(qargs)
        {
        }

        MsgQueue() {}

        ~MsgQueue() {}

        // 通过获取持久化参数字符串来初始化持久化参数，格式为key=value&key=value&key=value&...
        void setArgs(const std::string &str_args)
        {
            std::vector<std::string> sub_args;
            NS_Helper::String::split(str_args, "&", sub_args);

            for (auto &str : sub_args)
            {
                size_t pos = str.find("=");
                std::string key = str.substr(0, pos);
                std::string value = str.substr(pos + 1);
                args[key] = value;
            }
        }

        // 以上述格式序列化返回参数
        std::string getArgs()
        {
            std::string ret;
            for (auto &e : args)
            {
                ret += e.first + "=" + e.second + "&";
            }

            return ret;
        }
    };

    using MsgQueueMap = std::unordered_map<std::string, MsgQueue::Ptr>;

    class MsgQueuePersist
    {
        const std::string create_sql = "create table if not exists msg_queue(\
                                        name varchar(32) primary key, \
                                        exclusive int, \
                                        auto_delete int, \
                                        args varchar(128));";
        const std::string drop_sql = "drop table msg_queue;";

    public:
        MsgQueuePersist(const std::string &path)
            : _helper(path)
        {
            std::string parentpath = NS_Helper::FileHelper::getParentDirectory(path);
            NS_Helper::FileHelper::createDirectory(parentpath);
            assert(_helper.open());
        }

        // 创建消息队列数据表
        void createTable()
        {
            assert(_helper.insert(create_sql));
        }
        // 删除消息队列数据表
        void deleteTable()
        {
            assert(_helper.erase(drop_sql));
        }
        // 插入消息队列数据
        bool insert(MsgQueue::Ptr ptr)
        {
            std::stringstream ss;
            ss << "insert into msg_queue values";
            ss << "(" << "'" << ptr->name << "', ";
            ss << ptr->exclusive << ", ";
            ss << ptr->auto_delete << ", ";
            ss << "'" << ptr->getArgs() << "'" << ");";

            if (!_helper.insert(ss.str()))
            {
                DLOG("持久化消息队列数据失败，执行语句: %s", ss.str().c_str());
                return false;
            }

            return true;
        }

        // 删除消息队列数据
        void erase(const std::string &name)
        {
            std::stringstream ss;
            ss << "delete from msg_queue where name = ";
            ss << "'" << name << "';";
            if (!_helper.insert(ss.str()))
            {
                DLOG("删除持久化消息队列数据失败，执行语句: %s", ss.str().c_str());
            }
        }
        // 获取指定消息队列数据
        MsgQueue::Ptr selectOne(const std::string &name)
        {
            std::stringstream ss;
            ss << "select name, exclusive, auto_delete, args from msg_queue where name = ";
            ss << "'" << name << "';";

            MsgQueue::Ptr ret = std::make_shared<MsgQueue>();
            if (!_helper.select(ss.str(), selectOneCallback, ret))
            {
                DLOG("查询持久化消息队列数据失败，执行语句: %s", ss.str().c_str());
            }

            return ret;
        }

        // 获取所有持久化消息队列数据
        MsgQueueMap recovery()
        {
            std::stringstream ss;
            ss << "select name, exclusive, auto_delete, args from msg_queue;";

            MsgQueueMap mapper;
            if (!_helper.select(ss.str(), selectCallback, mapper))
            {
                DLOG("查询持久化消息队列数据失败，执行语句: %s", ss.str().c_str());
            }

            DLOG("恢复历史消息队列，消息队列数量：%d", (int)mapper.size());

            return mapper;
        }

        // 删除所有消息队列数据
        void clear()
        {
            std::stringstream ss;
            ss << "delete from msg_queue";
            if (!_helper.erase(ss.str()))
            {
                DLOG("删除所有持久化消息队列数据失败，执行语句: %s", ss.str().c_str());
            }
        }

        ~MsgQueuePersist() {}

    private:
        static int selectOneCallback(void *arg, int col_num, char **col_data, char **col_name)
        {
            MsgQueue::Ptr *ptr = static_cast<MsgQueue::Ptr *>(arg);
            (*ptr)->name = col_data[0];
            (*ptr)->exclusive = static_cast<bool>(std::stoi(col_data[1]));
            (*ptr)->durable = true;
            (*ptr)->auto_delete = static_cast<bool>(std::stoi(col_data[2]));

            // 防止存入的args是一个空对象
            if (col_data[3])
                (*ptr)->setArgs(col_data[3]);

            return 0;
        }

        static int selectCallback(void *arg, int col_num, char **col_data, char **col_name)
        {
            MsgQueueMap *map = static_cast<MsgQueueMap *>(arg);
            MsgQueue::Ptr ptr = std::make_shared<MsgQueue>();
            ptr->name = col_data[0];
            ptr->exclusive = static_cast<bool>(std::stoi(col_data[1]));
            ptr->durable = true;
            ptr->auto_delete = static_cast<bool>(std::stoi(col_data[2]));

            // 防止存入的args是一个空对象
            if (col_data[3])
                ptr->setArgs(col_data[3]);

            map->insert(std::make_pair(ptr->name, ptr));

            return 0;
        }

    private:
    NS_Helper::SQLite3Helper _helper;
    };

    class MsgQueueManager
    {
    public:
    using Ptr = std::shared_ptr<MsgQueueManager>;
        MsgQueueManager(const std::string &filename) : _persist(filename)
        {
            _persist.createTable();
            // 将数据库中持久化的所有消息队列恢复到内存中
            _msg_queues = _persist.recovery();
        }

        // 声明消息队列
        bool declareMsgQueue(const std::string &name,
                             bool exclusive,
                             bool durable, bool auto_delete,
                             const google::protobuf::Map<std::string, std::string> &args)
        {
            std::unique_lock<std::mutex> ul(_mtx);

            DLOG("参数消息队列是否持久化: %d", durable);
            // 如果存在，则返回
            if (_msg_queues.find(name) != _msg_queues.end())
                return true;

            MsgQueue::Ptr ptr = std::make_shared<MsgQueue>();
            ptr->name = name;
            ptr->exclusive = exclusive;
            ptr->durable = durable;
            ptr->auto_delete = auto_delete;
            ptr->args = args;
            _msg_queues.insert(std::make_pair(name, ptr));

            // 如果是持久化的消息队列，则存储到数据库表中
            DLOG("消息队列是否持久化: %d", durable);
            if (durable)
            {
                return _persist.insert(ptr);
            }
            return true;
        }

        // 删除指定消息队列数据
        void deleteMsgQueue(const std::string &name)
        {
            std::unique_lock<std::mutex> ul(_mtx);
            // 如果不存在，则返回
            if (_msg_queues.find(name) == _msg_queues.end())
                return;

            if (_msg_queues[name]->durable)
                _persist.erase(name);

            _msg_queues.erase(name);
        }
        // 该接口只能供外界使用，因为这里面也会加锁
        bool exists(const std::string &name)
        {
            std::unique_lock<std::mutex> ul(_mtx);
            return _msg_queues.find(name) != _msg_queues.end();
        }

        MsgQueue::Ptr selectOne(const std::string &name)
        {
            std::unique_lock<std::mutex> ul(_mtx);
            if (_msg_queues.find(name) == _msg_queues.end())
                return nullptr;

            return _msg_queues[name];
        }

        size_t size()
        {
            std::unique_lock<std::mutex> ul(_mtx);
            return _msg_queues.size();
        }

        const MsgQueueMap& getMsgQueues()
        {
            std::unique_lock<std::mutex> ul(_mtx);
            return _msg_queues;
        }
 
        // 删除所有消息队列数据
        void clear()
        {
            std::unique_lock<std::mutex> ul(_mtx);
            _persist.clear();
            _msg_queues.clear();
        }

        ~MsgQueueManager() {}

    private:
        // 在访问消息队列数据时，必定会使用到多线程
        std::mutex _mtx;
        // 对持久化消息队列数据进行管理
        MsgQueuePersist _persist;
        // 对内存中的消息队列进行管理
        MsgQueueMap _msg_queues;
    };

}

#endif